package com.ruicar.afs.cloud.account.common.run;

import cn.hutool.core.collection.CollectionUtil;
import com.ruicar.afs.cloud.account.common.dto.AccountVoucherInfoDto;
import com.ruicar.afs.cloud.account.common.mapper.VoucherFlowInfoMapper;
import com.ruicar.afs.cloud.account.common.processor.constant.VoucherConstant;
import com.ruicar.afs.cloud.account.common.service.VoucherFlowInfoService;
import com.ruicar.afs.cloud.common.core.enums.AfsEnumUtil;
import com.ruicar.afs.cloud.common.core.util.IResponse;
import com.ruicar.afs.cloud.common.modules.contract.enums.VoucherDataSources;
import com.ruicar.afs.cloud.common.modules.contract.enums.VoucherStatusEnum;
import com.ruicar.afs.cloud.common.vo.VoucherFlowInfoVo;
import com.ruicar.afs.cloud.common.voucher.VoucherBaseInfo;
import com.ruicar.afs.cloud.common.voucher.handle.VoucherCaches;
import com.ruicar.afs.cloud.common.voucher.handle.VoucherHelper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.text.MessageFormat;
import java.util.*;
import java.util.concurrent.*;

/**
 * 财务凭证service
 */

@Slf4j
@Service
@AllArgsConstructor
@Component
public class VoucherService {
    private static final ExecutorService EXECUTOR_SERVICE = new ThreadPoolExecutor(10, 10,
            0L, TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<Runnable>(1024));
    private final CaseServiceRunner caseServiceRunner;
    private final ContractServiceRunner contractServiceRunner;
    private final FinanceServiceRunner financeServiceRunner;
    private final ManageServiceRunner manageServiceRunner;
    private final VoucherFlowInfoMapper voucherFlowInfoMapper;
    private final VoucherFlowInfoService voucherFlowInfoService;

    //查询凭证业务数据
    public void timingTriggerGeneratingBaseVoucher() {
        List<VoucherFlowInfoVo> list = voucherFlowInfoMapper.queryVoucherFlow(AfsEnumUtil.key(VoucherStatusEnum.NOT_CREATED), VoucherConstant.querySize);
        if (CollectionUtil.isNotEmpty(list)) {
            handleFlows(list);
        }
    }

    /**
     * 处理凭证流水信息
     * @param list
     */
    public void handleFlows(List<VoucherFlowInfoVo> list) {
        CountDownLatch countDownLatch = new CountDownLatch(list.size());
        try {
            for (VoucherFlowInfoVo vo : list) {
                EXECUTOR_SERVICE.submit(new FlowVoucherRunner(vo, countDownLatch));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                countDownLatch.await();
            } catch (InterruptedException e) {
                log.error("", e);
            }
        }
    }

    @AllArgsConstructor
    class FlowVoucherRunner implements Runnable {
        private VoucherFlowInfoVo vo;
        private CountDownLatch countDownLatch;

        @Override
        public void run() {
            try {
                handleFlowingWater(vo);
            } catch (Exception e) {
                log.error("", e);
                //保存错误信息
                voucherFlowInfoService.handleFlowingErrMsg(vo.getId(), e.getMessage());
            } finally {
                countDownLatch.countDown();
            }
        }
    }

    public void handleFlowingWater(VoucherFlowInfoVo voucherFlowInfo) {
        VoucherHelper.checkUpdate();
        //根据埋点编号获取凭证事件相对应模板id
        List<Long> ids = VoucherCaches.getEvents(voucherFlowInfo.getBuriedPointNo());
        Map<VoucherDataSources, List<Long>> map = new HashMap<>();
        for (Long id : ids) {
            VoucherBaseInfo info = VoucherCaches.getVoucherInfo(id);
            if (!map.containsKey(info.getVoucherInfo().getDataSources())) {
                List<Long> longs = new ArrayList<>();
                longs.add(id);
                map.put(info.getVoucherInfo().getDataSources(), longs);
            } else {
                List<Long> longs = map.get(info.getVoucherInfo().getDataSources());
                longs.add(id);
                map.put(info.getVoucherInfo().getDataSources(), longs);
            }
        }
        List<AccountVoucherInfoDto> dtos = new ArrayList<>();
        Iterator it = map.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            VoucherDataSources dataSources = (VoucherDataSources) entry.getKey();
            List<Long> longList = (List<Long>) entry.getValue();
            IResponse iResponse = null;
            switch (dataSources) {
                case CASE_SERVICE:
                    iResponse = caseServiceRunner.execute(voucherFlowInfo, longList);
                    if (CollectionUtil.isNotEmpty((Collection<? extends AccountVoucherInfoDto>) iResponse.getData())) {
                        dtos.addAll((Collection<? extends AccountVoucherInfoDto>) iResponse.getData());
                    }
                    break;
                case CONTRACT_SERVICE:
                    iResponse = contractServiceRunner.execute(voucherFlowInfo, longList);
                    if (CollectionUtil.isNotEmpty((Collection<? extends AccountVoucherInfoDto>) iResponse.getData())) {
                        dtos.addAll((Collection<? extends AccountVoucherInfoDto>) iResponse.getData());
                    }
                    break;
                case FINANCE_SERVICE:
                    iResponse = financeServiceRunner.execute(voucherFlowInfo, longList);
                    if (CollectionUtil.isNotEmpty((Collection<? extends AccountVoucherInfoDto>) iResponse.getData())) {
                        dtos.addAll((Collection<? extends AccountVoucherInfoDto>) iResponse.getData());
                    }
                    break;
                case MANAGE_SERVICE:
                    iResponse = manageServiceRunner.execute(voucherFlowInfo, longList);
                    if (CollectionUtil.isNotEmpty((Collection<? extends AccountVoucherInfoDto>) iResponse.getData())) {
                        dtos.addAll((Collection<? extends AccountVoucherInfoDto>) iResponse.getData());
                    }
                    break;
                default:
                    log.error("凭证数据来源：[{}]，凭证方法未实现", AfsEnumUtil.desc(dataSources));
                    Assert.isTrue(false,MessageFormat.format("流水号：[{0}],凭证数据来源：[{0}]，凭证方法未实现", voucherFlowInfo.getTransNo(), AfsEnumUtil.desc(dataSources)));
                    break;
            }
        }
        voucherFlowInfoService.handleFlowingStatus(dtos, voucherFlowInfo);
    }

}


